/*
 * Copyright (c) 2006-2021, Ulandlink Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2022-11-17     xpw          first version
 * 2023-01-18     xpw          sync
 * 2023-02-20     xpw          sync
 */
 
#include <stdint.h>
#include <string.h>

#if defined(RT_USING_NETDEV)
#include <netdev.h>
#endif

#define LOG_TAG              "http.srv"
#define LOG_LVL               LOG_LVL_INFO  
#include <at_log.h>

#include <at_socket.h>
#include <at_device.h>

#include <http_pub.h>

#if HTTP_SERVER_ENABLE

#include <http_server.h>
#include <http_parse.h>
#include <http_utils.h>


#define HTTP_THREAD_STACKSIZE       (9 * 1024)
#define HTTP_PRIORITY               20

#define AT_SERVER_NUM_MAX           4

/* define http server event */
static struct rt_event http_server_event;

static rt_bool_t init_flag = RT_FALSE;

static rt_bool_t stop = RT_FALSE;

static int server_sockets[AT_SERVER_NUM_MAX];
static int server_num = AT_SERVER_NUM_MAX;

static void http_server_thread(void *parameter)
{
    int fd;
    char *ptr;
    rt_thread_t tid;
    rt_bool_t arg = RT_FALSE;
    int i, length, ret, socket;
    http_request_t request = {0};
    struct at_socket *sock = RT_NULL;
    struct at_device *device = RT_NULL;
    
    device = (struct at_device *)parameter;
    
    for (i = 0; i < server_num; i ++) {
        server_sockets[i] = -1;
    }
   
    /* create socket listener */
    for (i = 0; i < server_num; i ++) {
        server_sockets[i] = at_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (server_sockets[i]  < 0) {
            LOG_E("create at socket %d failed.", i);
            goto __exit;
        }
        LOG_D("server socket %d(device: %d) created.", i, server_sockets[i]);
    }
    
    i = 0;
    while(1) {
        socket = server_sockets[i];
        rt_memset(&request, 0, sizeof(http_request_t));
        
        if (http_recv_request(socket, &request)) {
            //http_print_request(socket, &request);
            http_resp_request(socket, &request);
            
            if (request.content_length > 0) {
                rt_free(request.content_buffer);
            }
        }
        
        /* continue to read next socket */
        rt_thread_mdelay(50);
        i ++;
        if (i >= server_num) {
            i = 0;
        }
        
        if (stop) {
            goto __exit;
        }
    }

__exit:
    
    at_device_control(device, AT_DEVICE_CTRL_SERVER, &arg);
    
    for (int j = 0; j < server_num; j ++) {
        if (server_sockets[j] >= 0) {
            at_closesocket(server_sockets[j]);
            server_sockets[j] = -1;
        }
    }
    
    init_flag = RT_FALSE;
    
    if (stop) {
        LOG_I("http server thread exit, all socket listener has been closed.");
        stop = RT_FALSE;
    } else {
        LOG_E("http server thread exit, all socket listener has been closed.");
    }
}

rt_bool_t is_server_socket(int socket)
{
    for (int i = 0; i < server_num; i ++) {
        if (server_sockets[i] == socket) {
            return RT_TRUE;
        }
    }
    return RT_FALSE;
}

void http_server_start(void)
{
    rt_thread_t tid;
    rt_bool_t arg = RT_TRUE;
    static struct at_device *device = RT_NULL;
    
    device = at_device_get_by_name(AT_DEVICE_NAMETYPE_NETDEV, "esp32");
    if (device == RT_NULL) {
        LOG_E("device esp32 not found.");
        return;
    }
    
    if (init_flag == RT_FALSE) {
        tid = rt_thread_create( "http_server",
                                http_server_thread, 
                                device,
                                HTTP_THREAD_STACKSIZE, 
                                HTTP_PRIORITY, 
                                5);

        if (tid != RT_NULL) {
            at_device_control(device, AT_DEVICE_CTRL_SERVER, &arg);
            init_flag = RT_TRUE;
            rt_thread_startup(tid);
            LOG_I("http server start.");
        } else {
            LOG_E("http server start failed.");
        }
    } else {
        LOG_W("http server is running.");
    }
}
MSH_CMD_EXPORT(http_server_start, http server start);

void http_server_stop(void)
{
    if (init_flag == RT_TRUE) {
        stop = RT_TRUE;
        
        while (stop) {
            rt_thread_mdelay(100);
        }
        LOG_I("http server stopped.");
        return;
    }
    
    LOG_W("http server already stopped.");
}
MSH_CMD_EXPORT(http_server_stop, http server stop);

void http_server_deinit(void)
{
    init_flag = RT_FALSE;
    
    for (int j = 0; j < server_num; j ++) {
        if (server_sockets[j] >= 0) {
            at_closesocket(server_sockets[j]);
            server_sockets[j] = -1;
        }
    }
}

void http_server_event_send(uint32_t event)
{
	rt_event_send(&http_server_event, event);
}

void http_server_event_recv(uint32_t event_set, rt_int32_t timeout, uint32_t *recv_event)
{
    *recv_event = 0;
    rt_event_recv(&http_server_event, event_set,
						  RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
						  timeout, recv_event);
}

#endif
